﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Data.SqlClient;
using System.Collections;
using StockEOD.Objects;
using StockEOD.Constants;
using SQLManager;

namespace StockEOD
{
    
    public class Importer
    {
        public static event StatusMessageDelgate OnStatusMessage;
        public static event PercentDoneDelegate OnPercentCompleteChange;
        private static void firePercentCompleteChanged(float perc)
        {
            if (OnPercentCompleteChange != null)
            {
                OnPercentCompleteChange(perc);
            }
        }

        public static void GetEodFiles(DirectoryInfo destinationFolder)
        {
            //string s = GetDownloadFile(Settings1.Default.StockURLPattern);
            
        }
        public static void fireOnStatusMessage(string message)
        {
            if (OnStatusMessage != null)
                OnStatusMessage(message);
        }
        public static List<Market> ExchangeCodesFromFile(DirectoryInfo dir)
        {
            string namesDir = Path.Combine(dir.FullName ,@"Names");
            if (File.Exists(Path.Combine( namesDir, MessageConstants.EXCAHANGE_FILE_NAME)))
            {
                fireOnStatusMessage(string.Format("Found {0} parsing",Path.Combine( namesDir,MessageConstants.EXCAHANGE_FILE_NAME)));
                string[] lines = File.ReadAllLines(Path.Combine( namesDir,MessageConstants.EXCAHANGE_FILE_NAME));
                List<Market> markets = new List<Market>();
                
                for (int i = 1; i < lines.Length; i++)
                {
                    string[] line = lines[i].Split('\t');
                    markets.Add(new Market() { Code = line[0], Name = line[1] });
                    
                    fireOnStatusMessage(string.Format("Reading {0}",lines[i]));
                }

                return markets;

            }
            else {
                fireOnStatusMessage (string.Format(MessageConstants.COULD_NOT_FIND_FILE, Path.Combine(namesDir, MessageConstants.EXCAHANGE_FILE_NAME)));
                    
                return null;
            }
                
        }
        public static void ImportMarketNames(DirectoryInfo dir)
        {
            string namesDir =  dir.FullName + @"\Names\";
            AppDataDataContext context = new AppDataDataContext();
            int addedCount = 0;
            
            if(File.Exists(namesDir + "Exchanges.txt"))
            {
                string[] lines = File.ReadAllLines(Path.Combine( namesDir,MessageConstants.EXCAHANGE_FILE_NAME));
                for (int i = 1; i < lines.Length; i++)
                {
                    string[] items = lines[i].Split('\t');
                    if(! (context.Markets.Count(m => m.Code == items[0]) >0) )
                    {
                        Market mNew = new Market() { Name = items[1], Code =items[0] };
                        context.Markets.InsertOnSubmit(mNew);
                        if (OnStatusMessage != null)
                        {
                            OnStatusMessage(string.Format(MessageConstants.ADDING_ITEM , mNew.Code));
                        }
                        addedCount++;
                    }

                }
                if (addedCount > 0)
                {
                    context.SubmitChanges();
                    if (OnStatusMessage != null)
                    {
                        OnStatusMessage(string.Format(MessageConstants.ADDED_ITEM,addedCount));
                    }
                }
            }



        }

        public static int ImportTickers(DirectoryInfo dir, string IndexCode, bool forceCompare )
        {
            AppDataDataContext context = new AppDataDataContext();
            int countIndexDB = CountIndexDB(IndexCode, context);
            int countIndexFile = CountIndexFile(dir, IndexCode);
            int countTickersDB = CountTickersDB(IndexCode, context);
            int countTickersFile = CountTickersFile(dir,IndexCode);
            if (context.Markets.Count(m => m.Code == IndexCode) <= 0)
                ImportMarketNames(dir);
            if(context.Markets.Count(m => m.Code == IndexCode) > 0)
            {
                firePercentCompleteChanged(0);
                Market m = context.Markets.Single(mItem => mItem.Code == IndexCode);
                // Validate input data
                // Check that Index exists in db
                // Check that Index files exists
                // If the current market exists in both locations, then proceed with import
                if (countIndexDB == 1 && countIndexFile == 1)
                {
                    if (countTickersFile > countTickersDB)
                    { 
                        // Import missing tickers
                        // Inform observers of the action to perform
                        fireOnStatusMessage(string.Format("There are {0} tickers to import for {1}",countTickersFile-countTickersDB, IndexCode));
                        string file = string.Format("{0}{1}{2}.txt", dir.FullName, @"\Names\", IndexCode);
                        // Get all the market's tickers to import
                        string[] names = File.ReadAllLines(file);
                        int pos = 0;
                        // Get all fundamental data for this market.
                        Dictionary<string,FundamentalDetail> fundLookup = GetFundamentalsHash(dir,IndexCode);
                        for (int i = 1; i < names.Length; i++)
                        {// Loop through the tickers in this market.
                            

                            // Break out the columns in this ticker
                            firePercentCompleteChanged(((float)pos / names.Length) * 100);
                            pos++;
                            string[] items = names[i].Split('\t');
                            if (context.Tickers.Count(t => t.MarketId == m.Id && t.Symbol == items[0]) == 0)
                            {
                                //int existingSymbol = m.Tickers.Count(t => t.Symbol == items[0]);
                                FundamentalDetail fd = null;
                                Sector sCurrent = null;
                                Industry sInd = null;
                                Ticker tCurrent = null;
                                if (fundLookup.ContainsKey(items[0]))
                                {

                                    // Get the ticker's fundamentals
                                    fd = fundLookup[items[0]];
                                    if (fd != null)
                                    {
                                        // Get the ticker's sector
                                        sCurrent = GetOrCreateSector(fd.Sector, m, context);
                                        // Get the ticker's industry
                                        sInd = GetOrCreateIndustry(fd.Industry, sCurrent, context);
                                        // Get or create the Ticker
                                        tCurrent = GetOrCreateTicker( items[0], m, sInd, context);
                                        tCurrent.Name = fd.Name;

                                        tCurrent.Fundamentals.Add(new Fundamental()
                                        {
                                            Date = fd.Date,
                                            EPS = fd.EPS,
                                            PE = fd.PE,
                                            DPS = fd.DPS,
                                            PEG = fd.PEG,
                                            Ptb = fd.Ptb,
                                            DIVYield = fd.DIVYIELD,
                                            Pts = fd.Pts,
                                            Shares = fd.Shares
                                        });
                                    }


                                }
                                context.SubmitChanges();
                                if (tCurrent != null)
                                    fireOnStatusMessage(string.Format("Added {0}\t{1}\t{2}\t{3}", tCurrent.Symbol, tCurrent.Name, tCurrent.Industry.Name, tCurrent.Industry.Sector.Name));
                            }
                            else
                            {
                                fireOnStatusMessage(string.Format("{0} already exists", items[0]));
                            }



                        }
                        return countTickersFile - countTickersDB;
                    }
                    else if (countTickersFile == countTickersDB)
                    {
                        // Message that the counts match
                        fireOnStatusMessage(string.Format("All {0} tickers have already been imported for {1}", countTickersDB, IndexCode));
                        return 0;
                    }
                }
            }
            else if (OnStatusMessage != null)
            {
                OnStatusMessage(string.Format(MessageConstants.NOT_FOUND_IN_DB,IndexCode,"Markets"));
            }
            return 0;
        }

        public static Ticker GetOrCreateTicker(string symbol, Market mCurrent, Industry iCurrent, AppDataDataContext context)
        {
            int existingTicker = iCurrent.Tickers.Count(t => t.Symbol == symbol && t.MarketId == mCurrent.Id);
            Ticker tCurrent = null;
            if (existingTicker > 0)
            {
                return iCurrent.Tickers.Single(t => t.Symbol == symbol);
            }
            else
            {
                tCurrent = new Ticker() { Symbol = symbol, Industry = iCurrent, Market = iCurrent.Sector.Market };
                context.Tickers.InsertOnSubmit(tCurrent);
                context.SubmitChanges();
                return tCurrent;
            }
        }
        public static Industry GetOrCreateIndustry(string industryName, Sector sCurrent, AppDataDataContext context)
        {
            Industry iCurrent = null;
            int existingIndustry = sCurrent.Industries.Count(i => i.Name == industryName);
            if (existingIndustry > 0)
            {
                iCurrent = sCurrent.Industries.Single(i => i.Name == industryName);
                return iCurrent;
            }
            else
            {
                iCurrent = new Industry() { Name = industryName, Sector = sCurrent };
                context.Industries.InsertOnSubmit(iCurrent);
                context.SubmitChanges();
                return iCurrent;
            }
        }
        public static Sector GetOrCreateSector(string sectorName, Market m, AppDataDataContext context)
        {
            Sector sCurrent = null;
            int existingSector = m.Sectors.Count(s => s.Name == sectorName);
            if (existingSector > 0)
            {
                sCurrent = m.Sectors.Single(s => s.Name == sectorName);
                return sCurrent;
            }
            else
            {
                sCurrent = new Sector() { Name = sectorName, Market = m };
                context.Sectors.InsertOnSubmit(sCurrent);
                context.SubmitChanges();
                return sCurrent;
            }
            
        }
        public static Dictionary<string,FundamentalDetail>  GetFundamentalsHash(DirectoryInfo dir, string IndexCode)
        {
            Dictionary<string, FundamentalDetail> dictFund = new Dictionary<string, FundamentalDetail>();
            string fileFundamentals = string.Format("{0}{1}{2}.txt", dir.FullName, @"\Fundamentals\", IndexCode);
            
            List<FundamentalDetail> list;
            if(File.Exists(fileFundamentals))
            {
                list = FundamentalDetail.ParseTextFile(fileFundamentals);
                foreach(FundamentalDetail fdItem in list)
                {
                    if (!dictFund.ContainsKey(fdItem.Ticker))
                    {
                        dictFund.Add(fdItem.Ticker, fdItem);
                    }
                }
                
            }
            
            
            return dictFund;
        }
        public Sector CreateOrGetSector(string name, Market m, AppDataDataContext context)
        {
            if (context.Sectors.Count(s => s.Name == name && s.MarketId == m.Id) > 0)
            {
                return context.Sectors.Single(s => s.Name == name && s.MarketId == m.Id);
            }
            else
            {
                Sector sNew = new Sector() { Name = name, Market = m };
                context.Sectors.Attach(sNew);
                context.SubmitChanges();
                return sNew;
                     
            }

        }
        public static int CountTickersDB(string IndexCode, AppDataDataContext context)
        {
             
            if (context.Markets.Count(m => m.Code == IndexCode) > 0)
            {
                return context.Markets.Single(m => m.Code == IndexCode).Tickers.Count();
            }
            else
                return 0;

        }

        public static int CountTickersFile(DirectoryInfo dir, string IndexCode)
        {
            string file = string.Format("{0}{1}{2}.txt", dir.FullName, @"\Names\", IndexCode);
             if (File.Exists(file))
             {
                 string[] lines = File.ReadAllLines(file);
                 return lines.Length - 1;

             }
             else
                 return 0;

        }

        /// <summary>
        /// Gets the count of the number of indexes by the name specified in the database.
        /// Should only return 1 or 0
        /// </summary>
        /// <param name="IndexCode"></param>
        /// <returns></returns>
        public static int CountIndexDB(string IndexCode, AppDataDataContext context)
        {
            return context.Markets.Count(m => m.Code == IndexCode);
        }

        /// <summary>
        /// Count the number of Index name files for the provided index. 
        /// 1 is normal.  0 is missing.  >1 ???
        /// </summary>
        /// <param name="IndexCode"></param>
        /// <returns>1 or 0 (should never be > 1)</returns>
        public static int CountIndexFile(DirectoryInfo dir, string IndexCode)
        {
            string file =string.Format("{0}{1}{2}.txt", dir.FullName , @"\Names\",IndexCode);
            if (File.Exists(file)) return 1;
            else return 0;

        }

        private static DateTime ParseDate(string dString)
        {
            if (dString.Length < 8)
                throw new ArgumentException("The datetime must be 8 characters.", "dString");
            else
                return new DateTime(Convert.ToInt16(dString.Substring(0, 4)), Convert.ToInt16(dString.Substring(4, 2)), Convert.ToInt16(dString.Substring(6, 2)));
        }

        public static void DeleteAllData()
        {
            AppDataDataContext context = new AppDataDataContext();
            context.DailyDetails.DeleteAllOnSubmit(context.DailyDetails.ToList());
            context.MarketDays.DeleteAllOnSubmit(context.MarketDays.ToList());
            context.Markets.DeleteAllOnSubmit(context.Markets.ToList());
            context.SubmitChanges();
        }

        public static List<string> FindMissingMarketDates()
        {
            AppDataDataContext context = new AppDataDataContext();
            List<Market> markets =  context.Markets.ToList();
            List<MarketDay> days = context.MarketDays.ToList();
            List<DailyDetail> ddList = null;
            List<string> messages = new List<string>();
            foreach (Market m in markets)
            {
                //foreach(MarketDay d in days.Where(di => di.Market.Name == m.Name))
                //{
                //    var qdays = (from dd in m.DailyDetails
                //                 where dd.Date == d.Date 
                //                 select dd);
                //    if(qdays.Count() < 1)
                //    {
                //        messages.Add(string.Format("Market : {0} Day: {1} has no market data.",m.Name,d.Date));
                //    }
                //}

            }
            return messages;


        }
        

        public static bool ImportDailyDetailFile(FileInfo sourceFile)
        {
            AppDataDataContext context = new AppDataDataContext();
            string fMarketName = sourceFile.Name.Split('_')[0];
            if (!String.IsNullOrEmpty(fMarketName))
            {
                Market fileMarket;
                if (context.Markets.Count(m => m.Name == fMarketName) > 0)
                {
                    fileMarket = context.Markets.Single(m => m.Name == fMarketName);
                }
                else
                {
                    fileMarket = new Market(){ Name=fMarketName};
                    context.Markets.InsertOnSubmit(fileMarket);
                    context.SubmitChanges();
                    
                }
                string[] lines = File.ReadAllLines(sourceFile.FullName);

                DateTime marketDate = ParseDate(lines[1].Split(',')[2]);
                MarketDay currentMD;
                if (context.MarketDays.Count(md => md.Date == marketDate && md.Market == fileMarket) > 0)
                {
                    return false; 
                    
                }
                else
                {
                    currentMD = new MarketDay() { Market = fileMarket, Date = marketDate };
                    
                    context.MarketDays.InsertOnSubmit(currentMD);
                    context.SubmitChanges();
                }
                for(int i = 1; i<lines.Count(); i++)
                {
                    if (!lines[i].StartsWith("<"))
                    {
                        string[] vals = lines[i].Split(',');
                        if (vals.Count() >= 8)
                        {
                            DailyDetail dd = new DailyDetail()
                            {
                                Ticker = GetOrCreateTicker( vals[0],fileMarket ,null,context), 
                                Per = vals[1],
                                Date = ParseDate(vals[2]),
                                Open = Convert.ToDouble(vals[3]),
                                High = Convert.ToDouble(vals[4]),
                                Low = Convert.ToDouble(vals[5]),
                                Close = Convert.ToDouble(vals[6]),
                                Vol = Convert.ToDouble(vals[7]),
                                //Oi = Convert.ToDouble(vals[8])
                            };
                            currentMD.DailyDetails.Add(dd);
                            context.DailyDetails.InsertOnSubmit(dd);
                        }
                        else
                            throw new ArgumentException("Row did not have 8 columns","vals.count");

                        
                        
                    }
                }
                context.SubmitChanges();

                
            }
            return true;
        }
    }
}
